1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::app::event::{Event, SessionMessage, StateChange};
use crate::app::state::_undo_stack::UndoStack;
use crate::app::state::{Consumed, SessionHelper, SessionState, StackSession};
use crate::app::{AeonError, DynError};
use crate::debug;
use crate::inference::inference_state::InferenceState;
use crate::sketchbook::data_structs::SketchData;
use crate::sketchbook::{JsonSerde, Sketch};

/// The state of one editor session.
///
/// An inference session is the session where the process of the inference is run on a given model.
pub struct InferenceSession {
    id: String,
    undo_stack: UndoStack,
    inference_state: InferenceState,
}

impl InferenceSession {
    pub fn new(id: &str) -> InferenceSession {
        InferenceSession {
            id: id.to_string(),
            undo_stack: UndoStack::default(),
            inference_state: InferenceState::new_empty(),
        }
    }
}

impl StackSession for InferenceSession {
    fn process_message(
        &mut self,
        message: &SessionMessage,
    ) -> Result<(Option<SessionMessage>, Option<StateChange>), DynError> {
        let path = message.message.path.clone();

        // if the state changed due to message processing, we'll have to reset the undo-redo stack
        // do not use messages that make these changes often
        let mut reset_stack = false;

        // message with sketch data sent from Editor session
        let result = if path == vec!["sketch_sent".to_string()] {
            if let Some(sketch_payload) = message.message.payload.clone() {
                let sketch = Sketch::from_custom_json(&sketch_payload)?;
                reset_stack = true;
                self.inference_state.set_sketch(sketch);
            } else {
                panic!("Message `sketch_sent` must always carry a payload.")
            }

            // no backend response is expected, but we must send refresh event to inform frontend
            // about the state change
            let sketch_data = SketchData::new_from_sketch(self.inference_state.get_sketch());
            let payload = sketch_data.to_json_str();
            let state_change = StateChange {
                events: vec![Event::build(&["inference", "get_sketch"], Some(&payload))],
            };
            Ok((None, Some(state_change)))
        } else {
            let error_msg = format!("`InferenceSession` cannot process path {:?}.", path);
            AeonError::throw(error_msg)
        };

        if reset_stack {
            debug!(
                "Back stack (of session {}) cleared due to backend change.",
                self.id
            );
            self.undo_stack.clear();
        }
        result
    }

    fn id(&self) -> &str {
        self.id.as_str()
    }

    fn undo_stack_mut(&mut self) -> &mut UndoStack {
        &mut self.undo_stack
    }

    fn undo_stack(&self) -> &UndoStack {
        &self.undo_stack
    }
}

impl SessionHelper for InferenceSession {}

impl SessionState for InferenceSession {
    fn perform_event(&mut self, event: &Event, at_path: &[&str]) -> Result<Consumed, DynError> {
        if let Some(at_path) = Self::starts_with("undo_stack", at_path) {
            self.undo_stack.perform_event(event, at_path)
        } else if let Some(at_path) = Self::starts_with("inference", at_path) {
            self.inference_state.perform_event(event, at_path)
        } else {
            Self::invalid_path_error_generic(at_path)
        }
    }

    fn refresh(&self, full_path: &[String], at_path: &[&str]) -> Result<Event, DynError> {
        if let Some(at_path) = Self::starts_with("undo_stack", at_path) {
            self.undo_stack.refresh(full_path, at_path)
        } else if let Some(at_path) = Self::starts_with("inference", at_path) {
            self.inference_state.refresh(full_path, at_path)
        } else {
            Self::invalid_path_error_generic(at_path)
        }
    }
}